﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using SLS.ExClassLib.Events; 
namespace SLS.ExClassLib.HLASimulation.Federation
{
    public class FEDTime
    {
        public string FedName;
        public DateTime MinTimeStamp;
        public DateTime MaxTimeStamp;
        public DateTime CurrentTime;
        public SortedDictionary<DateTime, int> MessageWallTimeTable;
        public FEDTime(string m_FedName)
        {
            FedName = m_FedName;
            MessageWallTimeTable = new SortedDictionary<DateTime, int>();
            MinTimeStamp = DateTime.MaxValue;
            MaxTimeStamp = DateTime.MinValue;
            CurrentTime = DateTime.MinValue;
        }
    }
    public class RTIMatrix
    {
        public static readonly RTIMatrix Instance = new RTIMatrix();
        ArrayList Federation;
        Dictionary<string, ArrayList> FederationList;
        public RTIMatrix()
        {
            FederationList = new Dictionary<string, ArrayList>();
            Federation = new ArrayList();
            FederationList.Add("UIFederation", Federation);
            Federation = new ArrayList();
            FederationList.Add("WFFederation", Federation);
            Federation = new ArrayList();
            FederationList.Add("HLAFederation", Federation);
            Federation = new ArrayList();
            FederationList.Add("WFServiceFederation", Federation);
            Federation = new ArrayList();
            FederationList.Add("DefaultFederation", Federation);

        }
        public ArrayList GetFederation(string m_FederationName)
        {
            ArrayList federation = null;
            try
            {
                lock (FederationList)
                {
                    if (!FederationList.ContainsKey(m_FederationName))
                    {
                        Tracer.Verbose(this.GetType().ToString(), m_FederationName + " can not find");
                        return federation;
                    }
                    federation = FederationList[m_FederationName];
                    if (federation == null)
                    {
                        federation = new ArrayList();
                        FederationList.Add(m_FederationName, federation);
                    }
                }
            }
            catch (Exception ex)
            {
                throw;
            }
            return federation;
        }
        public FEDTime GetFederateTime(string m_FedName, string m_FederationName)
        {
            ArrayList federation = GetFederation(m_FederationName);

            FEDTime fed = null;
            if (federation == null)
                return fed;

            try
            {
                lock (federation)
                {
                    var query = from FEDTime fedt in federation
                                where fedt.FedName == m_FedName
                                select fedt;
                    foreach (FEDTime fedt in query)
                    {
                        fed = fedt;
                    }
                    if (fed == null)
                    {
                        fed = new FEDTime(m_FedName);
                        federation.Add(fed);
                    }
                }
            }
            catch (Exception ex)
            {
                throw;
            }
            return fed;
        }
        public DateTime GetMinFederateTime(string m_FederateName, string m_FederationName)
        {
            DateTime timestamp = DateTime.Now;
            try
            {
                FEDTime fed = GetFederateTime(m_FederateName, m_FederationName);
                timestamp = fed.MinTimeStamp;
            }
            catch (Exception ex)
            {
                throw;
            }
            return timestamp;
        }
        public DateTime GetMaxFederateTime(string m_FederateName, string m_FederationName)
        {
            DateTime timestamp = DateTime.Now;
            try
            {
                FEDTime fed = GetFederateTime(m_FederateName, m_FederationName);
                timestamp = fed.MaxTimeStamp;
            }
            catch (Exception ex)
            {
                throw;
            }
            return timestamp;
        }
        public DateTime RegulateFederateCurrentTime(string m_FederateName, string m_FederationName, DateTime currenttime)
        {
            DateTime timestamp = DateTime.Now;
            try
            {
                timestamp = currenttime;
                FEDTime fed = GetFederateTime(m_FederateName, m_FederationName);
                fed.CurrentTime = timestamp;
            }
            catch (Exception ex)
            {
                throw;
            }
            return timestamp;
        }
        public DateTime UpdateFederateTime(string m_FederateName, string m_FederationName, DateTime currenttime, bool flagAddMessage = true)
        {
            DateTime timestamp = DateTime.Now;
            try
            {
                timestamp = currenttime;
                FEDTime fed = GetFederateTime(m_FederateName, m_FederationName);
                if (fed == null)
                    return timestamp;
                lock (fed)
                {
                    if (fed.MinTimeStamp > timestamp)
                    {
                        fed.MinTimeStamp = timestamp;
                    }
                    if (fed.MaxTimeStamp < timestamp)
                    {
                        fed.MaxTimeStamp = timestamp;
                    }
                    if (flagAddMessage)
                    {
                        int msgnum = 0;
                        if (fed.MessageWallTimeTable.ContainsKey(timestamp))
                        {
                            msgnum = (int)fed.MessageWallTimeTable[timestamp];
                            fed.MessageWallTimeTable[timestamp] = msgnum++;
                        }
                        else
                        {
                            fed.MessageWallTimeTable.Add(timestamp, 1);
                        }
                        Tracer.Info("RTI:"+fed.FedName, timestamp.ToString() + " has messges: " + fed.MessageWallTimeTable[timestamp].ToString()+" to be Removed!");
                    }
                }
            }
            catch (Exception ex)
            {
                throw;
            }
            return timestamp;
        }
        public int GetMessgeOnWallTimeTable(string m_FederateName, string m_FederationName, DateTime TimeStamp,int ClientMsgNum)
        {
            FEDTime fed = GetFederateTime(m_FederateName, m_FederationName);
            int msgnum = 0;
            int AllReceived = 0;
            lock (fed)
            {
                foreach (KeyValuePair<DateTime, int> kp in fed.MessageWallTimeTable)
                {
                    if (kp.Key <= TimeStamp)
                        msgnum += kp.Value;
                }
                if (msgnum == ClientMsgNum)
                {
                    AllReceived = 1;
                    DelMessgeOnWallTimeTable(m_FederateName, m_FederationName, TimeStamp);
                }
            }
            return AllReceived;
        }
        public void DelMessgeOnWallTimeTable(string m_FederateName, string m_FederationName, DateTime TimeStamp)
        {
            FEDTime fed = GetFederateTime(m_FederateName, m_FederationName);
            ArrayList keylist = new ArrayList();
            lock (fed)
            {
                foreach (KeyValuePair<DateTime, int> kp in fed.MessageWallTimeTable)
                {
                    if (kp.Key <= TimeStamp)

                        keylist.Add(kp.Key);
                }
                foreach (DateTime timestamp in keylist)
                {
                    if (fed.MessageWallTimeTable.ContainsKey(timestamp))
                    {
                        fed.MessageWallTimeTable.Remove(timestamp);
                        Tracer.Info(fed.FedName, " Removed " + timestamp);
                    }
                } 
            }
        }

    }
}
